var _Storage = require('utils/storage.js');

// ==========================
// CellCount
// ==========================
function CellCount() {
    this.mRank = 0;
    this.mCount = 0;
}
CellCount.prototype.init = function (rank) {
    this.mRank = rank;
    return this;
};
CellCount.prototype.load = function (obj) {
    this.mRank = obj.rank || 3;
    this.mCount = obj.count || 0;
    return this;
};
CellCount.prototype.save = function (obj) {
    obj.rank = this.mRank;
    obj.count = this.mCount;
};
CellCount.prototype.getRank = function () {
    return this.mRank;
};
CellCount.prototype.setCount = function (c) {
    this.mCount = c;
};
CellCount.prototype.getCount = function () {
    return this.mCount;
};
CellCount.prototype.toJSON = function () {
    return {rank: this.mRank, count: this.mCount};
};
CellCount.prototype.toString = function () {
    return JSON.stringify(this.toJSON());
};
/**
 * little first
 * @param c1
 * @param c2
 * @returns {number}
 */
function compCount(c1, c2) {
    return c1.mRank - c2.mRank;
}

// ==========================
// Statistics
// ==========================
function Statistics() {
    this.mHighScore = 0;
    this.mHighRank = 0;
    this.mGroups = [];

    this.mStorage = _Storage.internal('statistics.json', {});
}
Statistics.prototype.getHighScore = function () {
    return this.mHighScore;
};
Statistics.prototype.getHighRank = function () {
    return this.mHighRank;
};
Statistics.prototype.getGroups = function () {
    return this.mGroups;
};
Statistics.prototype.updateRecord = function (record) {
    if (this.__updateData(record)) {
        this.save();
    }
};
Statistics.prototype.findCreateGroup = function (rank) {
    for (var i = 0, gs = this.mGroups, l = gs.length; i < l; i++) {
        if (gs[i].getRank() == rank) {
            return gs[i];
        }
        if (gs[i].getRank() > rank) {
            var g = new CellCount().init(rank);
            gs.splice(i, 0, g);
            return g;
        }
    }

    // insert to last place
    var g = new CellCount().init(rank);
    this.mGroups.push(g);
    return g;
};
/**
 * update ranks
 * @param record
 * @returns {boolean} if rank has been updated
 */
Statistics.prototype.__updateData = function (record) {
    // update score
    var changed = false;
    if (record.getScore() > this.mHighScore) {
        this.mHighScore = record.getScore();
        changed = true;
    }

    // count
    var cells = [].concat(record.getCells());
    var rank = 3;
    while (cells.length > 0) {
        var count = 0;
        for (var i = 0; i < cells.length; i++) {
            if (cells[i] < rank) {
                cells.splice(i, 1);
                i--;
                continue;
            }
            if (cells[i] == rank) {
                count++;
                cells.splice(i, 1);
                i--;
            }
        }

        if (count > 0) {
            var g = this.findCreateGroup(rank);
            if (g.getCount() < count) {
                g.setCount(count);
                changed = true;
            }
        }
        rank *= 2;
    }

    // update highest rank
    var highest = this.mGroups[this.mGroups.length - 1].getRank();
    if (highest > this.mHighRank) {
        this.mHighRank = highest
        changed = true;
    }

    return changed;
};
Statistics.prototype.validate = function () {
    // validate group 3,6,12,24,48...
    var start = 3;
    var last = 3;

    for (var i = 0; i < this.mGroups.length; i++) {
        var cellcount = this.mGroups[i];
        var rank = cellcount.getRank();

        while (start < rank) {
            start *= 2;
        }
        if (start > rank) {
            this.mGroups.splice(i, 1);
            i--;
        } else {// start == rank
            last = start;
            start *= 2;// next rank
        }
    }

    if (this.mHighRank != last) {
        this.mHighRank = last;
    }
};
// ---------------- save & load
Statistics.prototype.load = function () {
    var obj = this.mStorage.load();

    this.mHighScore = obj.highscore || 0;
    this.mHighRank = obj.highrank || 0;

    var data = obj.groups || [];
    for (var i = 0; i < data.length; i++) {
        this.mGroups.push(new CellCount().load(data[i]));
    }
    this.mGroups.sort(compCount);
    this.validate();
};
Statistics.prototype.save = function () {
    var obj = {};
    obj.highscore = this.mHighScore;
    obj.highrank = this.mHighRank;

    var groups = [];
    for (var i = 0; i < this.mGroups.length; i++) {
        groups.push(this.mGroups[i].toJSON());
    }
    obj.groups = groups;

    this.mStorage.save(obj);
};

module.exports = new Statistics();